package com.aidex.modules.service.impl;

import java.util.*;

import com.aidex.common.constant.Constants;
import com.aidex.common.constant.UserConstants;
import com.aidex.common.core.domain.TreeNode;
import com.aidex.common.core.domain.entity.SysDept;
import com.aidex.common.core.service.BaseTreeServiceImpl;
import com.aidex.common.exception.BizException;
import com.aidex.common.utils.NumberUtils;
import com.aidex.common.utils.PinYin4JCn;
import com.aidex.common.utils.StringUtils;
import com.aidex.common.utils.uuid.IdUtils;
import com.aidex.system.common.SysErrorCode;
import com.aidex.system.mapper.SysDeptMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.pagehelper.PageInfo;
import com.aidex.common.core.domain.BaseEntity;
import com.aidex.common.core.service.BaseServiceImpl;
import com.aidex.modules.mapper.ModDormBuildMapper;
import com.aidex.modules.domain.ModDormBuild;
import com.aidex.modules.service.ModDormBuildService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

/**
 * dormService业务层处理
 * @author anewhen
 * @email anewhen@foxmail.com
 * @date 2022-06-24
 */
@Service
@Transactional(readOnly = true)
public class ModDormBuildServiceImpl extends BaseTreeServiceImpl<ModDormBuildMapper, ModDormBuild> implements ModDormBuildService {

    private static final Logger log = LoggerFactory.getLogger(ModDormBuildServiceImpl.class);

    @Resource
    private ModDormBuildMapper mapper;

    private static final int ID_LIMIT = 500;

    /**
     * 获取单条数据
     * @param modDormBuild dorm
     * @return dorm
     */
    @Override
    public ModDormBuild get(ModDormBuild modDormBuild) {
        ModDormBuild dto = mapper.get(modDormBuild);
        return dto;
    }

//    /**
//     * 获取单条数据
//     * @param id dormid
//     * @return dorm
//     */
//    @Override
//    public ModDormBuild getById(String id) {
//        ModDormBuild dto = this.get(id);
//        return dto;
//    }

    /**
     * 查询dorm列表
     * @param modDormBuild dorm
     * @return dorm
     */
    @Override
    public List<ModDormBuild> findList(ModDormBuild modDormBuild) {
		List<ModDormBuild> modDormBuildList = mapper.findList(modDormBuild);
        return modDormBuildList;
    }

    /**
     * 分页查询dorm列表
     * @param modDormBuild dorm
     * @return dorm
     */
    @Override
    public PageInfo<ModDormBuild> findPage(ModDormBuild modDormBuild) {
		PageInfo<ModDormBuild> page = this.findPage(modDormBuild);
        return page;
    }

    /**
     * 保存dorm
     * @param modDormBuild
     * @return 结果
     */
    @Override
    public boolean save(ModDormBuild modDormBuild) {
        modDormBuild.setCurrentMembers(0);
        modDormBuild.setBuildPinyin(PinYin4JCn.getFullAndSimplePinYin(modDormBuild.getBuildName(),500));
        checkBuildNameUnique(modDormBuild);
        ModDormBuild parentBuild = mapper.get(modDormBuild.getParentId());
        if (null != parentBuild || StringUtils.isNotBlank(modDormBuild.getId())) {
            //没有父节点或者当前数据有ID(编辑跟节点时)
            //新增
            if (StringUtils.isEmpty(modDormBuild.getId())) {
                // 如果父节点不为正常状态,则不允许新增子节点
                if (!UserConstants.DEPT_NORMAL.equals(parentBuild.getStatus())) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptAlreadyUnNormal, "建筑停用，不允许新增子节点");
                }
                setTreeProperties(modDormBuild, null, Constants.OpType.insert);
                super.save(modDormBuild);
            } else {
                //编辑
                ModDormBuild oldBuild = mapper.get(modDormBuild);
                if (isMoveToSelfChildNode(modDormBuild, oldBuild)) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptMoveUnNormal, "非法移动，不允许将节点移动到自身或者子节点下");
                }
                List<ModDormBuild> updateChildList = new ArrayList<ModDormBuild>();
                if (modDormBuild.getParentId().equals(modDormBuild.getId())) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptIdNotEqualParentId, "修改部门失败，上级部门不能是自己");
                }
                if (StringUtils.equals(UserConstants.DEPT_DISABLE, modDormBuild.getStatus()) && mapper.selectNormalChildByParentIds(modDormBuild.getParentIds()) > 0) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptHasNormalChild, "该部门包含未停用的子部门，不允许标记为停用");
                }
                if("dept".equals(modDormBuild.getBuildType())){
                    //当修改类型为部门时需要判断当前节点下所有子孙节点中是否存在公司节点
//                    SysDept checkSysDept = sysDept;//避免对象引用
                    ModDormBuild checkSysDept = new ModDormBuild();
                    checkSysDept.setId(modDormBuild.getId());
                    checkSysDept.setBuildType("unit");
                    List<ModDormBuild> checkList = mapper.searchChildrenTypeByParentId(checkSysDept);
                    if(!CollectionUtils.isEmpty(checkList)){
                        throw new BizException(SysErrorCode.B_SYSDEPT_NoAllowUpdateType);
                    }
                }
                if (isUpdateTreeProperties(modDormBuild, oldBuild)) {
                    setTreeProperties(modDormBuild, oldBuild, Constants.OpType.update);
                    updateChildList = updateChildTreeProperties(modDormBuild, oldBuild);
                    if (!CollectionUtils.isEmpty(updateChildList)) {
                        mapper.updateDormChildren(updateChildList);
                    }
                }
                parentBuild = mapper.get(modDormBuild.getParentId());
                // 新的父节点变更为非叶子节点
                if (!Constants.TREE_ROOT.equals(modDormBuild.getParentId()) && parentBuild.getTreeLeaf().equals(Constants.TREE_LEAF_Y)) {
                    parentBuild.setTreeLeaf(Constants.TREE_LEAF_N);
                    super.save(parentBuild);
                }
                String oldParentId = oldBuild.getParentId();
                super.save(modDormBuild);
                // 判断原节点是否还有子节点，否则改为叶子节点
                if (!hasChildByDeptId(oldParentId)) {
                    ModDormBuild oldParentBuild = mapper.get(oldParentId);
                    oldParentBuild.setTreeLeaf(Constants.TREE_LEAF_Y);
                    super.save(oldParentBuild);
                }
            }
        } else {
            //新增根节点
            modDormBuild.setId(IdUtils.randomUUID());
            modDormBuild.setNewRecord(true);
            modDormBuild.setParentIds(modDormBuild.getId());
            // 设置当前树全路径排序
            Integer treeSort = modDormBuild.getTreeSort();
            String treeSorts = String.format("%06d", treeSort);
            modDormBuild.setTreeSorts(treeSorts);
            modDormBuild.setTreeLeaf(Constants.TREE_LEAF_Y);
            // 设置当前节点级别.
            modDormBuild.setTreeLevel(1);
            super.save(modDormBuild);
        }
        return Boolean.TRUE;
    }

    /**
     * 删除dorm信息
     * @param modDormBuild
     * @return 结果
     */
    @Override
    public boolean remove(ModDormBuild modDormBuild) {
        return super.remove(modDormBuild);
    }

    /**
     * 批量删除dorm
     * @param ids 需要删除的dormID
     * @return 结果
     */
    @Transactional(readOnly = false)
    @Override
    public int deleteModDormBuildByIds(String[] ids) {
        return mapper.deleteModDormBuildByIds(ids, BaseEntity.DEL_FLAG_DELETE);
    }

    @Override
    public void checkBuildNameUnique(ModDormBuild build) {
        ModDormBuild buildUnique = new ModDormBuild();
        buildUnique.setNotEqualId(build.getId());
        buildUnique.setBuildName(build.getBuildName());
        buildUnique.setParentId(build.getParentId());
        if (!CollectionUtils.isEmpty(mapper.findListWithUnique(buildUnique))) {
            throw new BizException(SysErrorCode.B_DORM_BUILDNameAlreadyExist);
        }
    }

    /**
     * 是否存在子节点
     *
     * @param buildId 建筑ID
     * @return 结果
     */
    @Override
    public boolean hasChildByDeptId(String buildId) {
        int result = findChildCountById(buildId);
        return result > 0;
    }

    @Override
    public List<ModDormBuild> listDataByLevel(int level, String parentId) {
        List<ModDormBuild> listData = new ArrayList<ModDormBuild>();
        level--;
        List<ModDormBuild> childrenList = findChildListByParentId(parentId);
        for (ModDormBuild dto : childrenList) {
            if ("n".equals(dto.getTreeLeaf()) && level > 0) {
                dto.setChildren(this.listDataByLevel(level, dto.getId()));
            } else {
                dto.setChildren(new ArrayList<>());
            }
            listData.add(dto);
        }
        return listData;
    }

    @Override
    public List<TreeNode> buildDormTree(int level, String parentId) {
        return this.buildDormTreeExcludeChild(level, parentId, "");
    }

    /**
     * 构建前端所需要树结构
     *
     * @param level     展开层级
     * @param parentId  父节点ID
     * @param excludeId 排除节点ID
     * @return
     */
    @Override
    public List<TreeNode> buildDormTreeExcludeChild(int level, String parentId, String excludeId) {
        List<TreeNode> listData = new ArrayList<TreeNode>();
        level--;
        List<ModDormBuild> childrenList = findChildListByParentId(parentId);
        // 拼接当前房间床位情况
        childrenList.forEach(e -> {
            if(StringUtils.equals(e.getBuildType(),"room")){
                StringBuffer sb = new StringBuffer();
                sb.append(e.getBuildName())
                        .append(" (")
                        .append(e.getCurrentMembers())
                        .append("/")
                        .append(e.getMembers()).append(")");
                e.setBuildName(sb.toString());
            }
        });
        for (ModDormBuild dorm : childrenList) {
            if (!dorm.getId().equals(excludeId)) {
                TreeNode treeNode = this.transToTreeNodeData(dorm);
                if ("n".equals(dorm.getTreeLeaf()) && level != 0) {
                    treeNode.setChildren(this.buildDormTreeExcludeChild(level, dorm.getId(), excludeId));
                } else {
                    treeNode.setChildren(null);
                }
                //不展开节点的父节点数据处理
                if (CollectionUtils.isEmpty(treeNode.getChildren())) {
                    treeNode.setChildren(null);
                }
                listData.add(treeNode);
            }
        }
        return listData;
    }

    @Override
    public List<TreeNode> search(String searchText) {
        List<TreeNode> tree = new ArrayList<TreeNode>();
        ModDormBuild queryParams = new ModDormBuild();
        queryParams.setSearchText(searchText);
        List<ModDormBuild> searchNodes = mapper.searchDormTree(queryParams);
        if (!CollectionUtils.isEmpty(searchNodes)){
            Set<String> treeIdSet = reDuplicationByTreePath(searchNodes);
            int i = 0;
            //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
            List<List<String>> idsList = new ArrayList<List<String>>();
            List<String> idList = new ArrayList<String>();
            for (String treeId : treeIdSet) {
                //当id个数超出限制后，则新new一个list来存放
                if(i % ID_LIMIT == 0 && i > 0){
                    idsList.add(idList);
                    idList = new ArrayList<String>();
                }
                idList.add(treeId);
                i++;
            }
            idsList.add(idList);
            List<ModDormBuild> allNodes = mapper.searchDormTreeByIds(idsList);
            tree = createTreeData(allNodes);
        }
        return tree;
    }

    @Override
    public List<Map<String,Object>> getDormInfoByIds(JSONObject dormIdsObj){
        String[] deptIds = dormIdsObj.getString("dormIds").split(";");
        int i = 0;
        //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
        List<List<String>> idsList = new ArrayList<List<String>>();
        List<String> idList = new ArrayList<String>();
        for (String deptId : deptIds) {
            //当id个数超出限制后，则新new一个list来存放
            if(i % 500 == 0 && i > 0){
                idsList.add(idList);
                idList = new ArrayList<String>();
            }
            idList.add(deptId);
            i++;
        }
        idsList.add(idList);
        return mapper.getDormInfoByIds(idsList);
    }

    /**
     *  组建树形结构
     * @param entityNodes 节点集合
     * @return List<VueNode>
     */
    private List<TreeNode> createTreeData(List<ModDormBuild> entityNodes) {
        List<TreeNode> list = transToTreeNodeData(entityNodes);
        List<TreeNode> tree = new ArrayList<TreeNode>();
        for (TreeNode treeNode : list) {
            //找到根节点
            if (Constants.TREE_ROOT.equals(treeNode.getParentId())) {
                tree.add(treeNode);
            }
            List<TreeNode> children = new ArrayList<TreeNode>();
            //再次遍历list，找到子节点
            for (TreeNode node : list) {
                if (node.getParentId().equals(treeNode.getId())) {
                    children.add(node);
                }
            }
            treeNode.setChildren(children);
            if (children.isEmpty()){
                treeNode.setIsLeaf(true);
            }
        }
        return tree;
    }

    /**
     *  将实体类集合转化成VueNode格式
     * @param entityNodes  实体类节点集合
     * @return List<VueNode>
     */
    private List<TreeNode> transToTreeNodeData(List<ModDormBuild> entityNodes) {
        List<TreeNode> treeNodes = new ArrayList<TreeNode>();
        for (ModDormBuild entityNode : entityNodes) {
            TreeNode treeNode = transToTreeNodeData(entityNode);
            treeNodes.add(treeNode);
        }
        return treeNodes;
    }

    /**
     *  将实体类转化成VueNode格式
     * @param entityNode  实体类节点集合
     * @return List<VueNode>
     */
    private TreeNode transToTreeNodeData(ModDormBuild entityNode) {
        TreeNode treeNode = new TreeNode();
        treeNode.setId(entityNode.getId());
        treeNode.setKey(entityNode.getId());
        treeNode.setTitle(entityNode.getBuildName());
        treeNode.setLabel(entityNode.getBuildName());
        treeNode.setSelectable(true);
        treeNode.setDisabled(false);
        treeNode.setDisableCheckbox(false);
        treeNode.setParentId(entityNode.getParentId());
        treeNode.setParentIds(entityNode.getParentIds());
        HashMap<String,Object> attr = new HashMap<>();
        attr.put("treeLeaf", entityNode.getTreeLeaf());
        attr.put("treeLevel", entityNode.getTreeLevel());
        attr.put("treePath", entityNode.getParentIds());
        attr.put("buildType", entityNode.getBuildType());
        attr.put("subtitle", entityNode.getBuildName());
        attr.put("deptPinyin", entityNode.getBuildPinyin());
        treeNode.setAttributes(attr);
        if (Constants.TREE_LEAF_Y.equals(entityNode.getTreeLeaf())){
            treeNode.setIsLeaf(true);
        } else{
            treeNode.setIsLeaf(false);
        }
        JSONObject slotsValue = new JSONObject();
        String buildType = StringUtils.isNotBlank(entityNode.getBuildType()) ? entityNode.getBuildType() : "";
        if ("build".equals(buildType)) {
            slotsValue.put("icon", "org");
            treeNode.setDisableCheckbox(true);
        } else if ("unit".equals(buildType)) {
            slotsValue.put("icon", "company");
            treeNode.setDisableCheckbox(true);
        } else if ("room".equals(buildType)) {
            slotsValue.put("icon", "dept");
            treeNode.setDisableCheckbox(false);
        } else if ("user".equals(buildType)) {
            slotsValue.put("icon", "user");
            treeNode.setDisableCheckbox(false);
        }
        JSONObject scopedSlotsValue = new JSONObject();
        scopedSlotsValue.put("title","title");
        scopedSlotsValue.put("attributes","attributes");
        treeNode.setSlots(slotsValue);
        treeNode.setScopedSlots(scopedSlotsValue);
        return treeNode;
    }


    public Integer findChildCountById(String buildId) {
        ModDormBuild build = new ModDormBuild();
        build.setParentId(buildId);
        return mapper.findCount(build);
    }

    /**
     * 根据parentIds去重
     * @param entityNodes entityNodes
     */
    private Set<String> reDuplicationByTreePath(List<ModDormBuild> entityNodes) {
        Set<String> treeIdSet = new HashSet<String>();
        for (ModDormBuild dto : entityNodes) {
            String treePath = dto.getParentIds();
            treeIdSet.addAll(Arrays.asList(treePath.split("/")));
        }
        return treeIdSet;
    }

    /**
     * 查询最大排序号
     *
     * @param build
     * @return
     */
    @Override
    public Integer findMaxSort(ModDormBuild build) {
        Integer maxSort = mapper.findMaxSort(build);
        return NumberUtils.nextOrder(null);
    }
}
